package com.jadesoft.common.web;

import java.lang.reflect.InvocationTargetException;
import java.lang.reflect.Method;
import java.lang.reflect.Modifier;
import java.sql.Timestamp;
import java.util.Map;

import javax.servlet.ServletRequest;
import javax.servlet.ServletResponse;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;

import org.apache.commons.lang.StringUtils;
import org.apache.struts.action.ActionForm;
import org.apache.struts.action.ActionForward;
import org.apache.struts.action.ActionMapping;
import org.apache.struts.actions.DispatchAction;
import org.springframework.web.multipart.MultipartFile;
import org.springframework.web.multipart.MultipartHttpServletRequest;

import com.jadesoft.account.entity.Enterprise;
import com.jadesoft.common.util.JustRenderResult;
import com.jadesoft.stock.entity.User;
import com.jadesoft.stock.util.Constants;
import com.sitechasia.webx.core.utils.populator.ConverterFactory;
import com.sitechasia.webx.core.utils.populator.PopulatorFactory;
import com.ufida.apps.common.BusinessServiceFactory;
import com.ufida.leaf.exception.BusinessException;

@SuppressWarnings("unchecked")
public class AjaxAction extends DispatchAction {
	public static final String JUST_RENDER_RESULT = "just_render_result";
	protected ActionForward dispatchMethod(ActionMapping mapping,
			ActionForm form, HttpServletRequest request,
			HttpServletResponse response, String name) throws Exception {
		log.info("char-set: "+request.getCharacterEncoding());
		Method method = getMethod(name);
		if (method == null)
			throw new NoSuchMethodException((new StringBuilder(
					"Can NOT find specified method: ")).append(name).toString());
		if (method.getReturnType() == ActionForward.class) {
			return super.dispatchMethod(mapping, form, request, response, name);
		}
		if(method.isAnnotationPresent(JustRenderResult.class)){
			response.setHeader(AjaxAction.JUST_RENDER_RESULT, "");
		}
		IResponseRenderer renderer = ResponseRenderFactory.getRenderer(request
				.getParameter("format"));
		try {
			Object result = exec(method, mapping, form);

			if (/**method.getReturnType() == void.class ||*/ response.isCommitted())
				return null;
			
			renderer.render(response, result, true);
		} catch (Exception e) {
			e.printStackTrace();
			log.error(e);
			if (e instanceof InvocationTargetException) {
				doOracleUniqueException(response, renderer, e);
			} else {
				renderer.render(response, e, false);
			}
		}

		return null;
	}

	private void doOracleUniqueException(HttpServletResponse response,
			IResponseRenderer renderer, Exception e) {
		String errmsg1 = null,errmsg2 = null ;
		Throwable a,b = null;
		a = ((InvocationTargetException) e).getTargetException();
		if(a != null) b = a.getCause();
		if(null != b){
			errmsg1 = b.getMessage();
		}
		if(null != b && null != b.getCause()){
			errmsg2 = b.getCause().getMessage();
		}
		if ((errmsg2 != null && errmsg2.contains("ORA-00001:"))
				|| (errmsg1 != null && errmsg1.contains("ORA-00001:"))) {
			renderer.render(response, new BusinessException("此刻编号存在冲突,请稍候再试!",
					e), false);
		} else if (a instanceof BusinessException) {
			renderer.render(response, e, false);
		} else {
			renderer.render(response, new BusinessException("很遗憾，您的操作没有成功！请与我们的客服取得联系！"),false);
		}
	}

	protected Method getMethod(String name) {
		if (!methods.containsKey(name))
			synchronized (methods) {
				if (!methods.containsKey(name)) {
					label0: for (Class clazz = getClass(); clazz != AjaxAction.class; clazz = clazz
							.getSuperclass()) {
						Method tempMethods[] = clazz.getDeclaredMethods();
						Method amethod[] = tempMethods;
						int i = 0;
						for (int j = amethod.length; i < j; i++) {
							Method tempMethod = amethod[i];
							if (Modifier.PUBLIC != tempMethod.getModifiers()
									|| !tempMethod.getName().equals(name))
								continue;
							methods.put(name, tempMethod);
							break label0;
						}
					}

				}
			}
		return (Method) methods.get(name);
	}

	private Object exec(Method method, ActionMapping mapping, ActionForm form)
			throws Exception {
		Class type[] = method.getParameterTypes();
		java.lang.annotation.Annotation annotationArray[][] = method
				.getParameterAnnotations();
		Object paramTarget[] = new Object[type.length];
		for (int i = 0; i < type.length; i++) {
			Class typeClasz = type[i];
			if (typeClasz == ActionMapping.class) {
				paramTarget[i] = mapping;
			} else if (typeClasz == ActionForm.class) {
				paramTarget[i] = form;
			} else if (ServletRequest.class.isAssignableFrom(typeClasz)) {
				paramTarget[i] = RequestContext.get().getRequest();
			} else if (ServletResponse.class.isAssignableFrom(typeClasz)) {
				paramTarget[i] = RequestContext.get().getResponse();
			} else if (MultipartFile.class.isAssignableFrom(typeClasz)) {
				java.lang.annotation.Annotation annotation[] = annotationArray[i];
				String fileName = ((Bind) annotation[0]).key();
				paramTarget[i] = ((MultipartHttpServletRequest) RequestContext
						.get().getRequest()).getFile(fileName);
			} else {
				java.lang.annotation.Annotation annotation[] = annotationArray[i];
				paramTarget[i] = getParameter(typeClasz,
						annotation.length == 0 ? null : (Bind) annotation[0]);
			}
		}

		return method.invoke(this, paramTarget);
	}

	/**
	 * 从request中获取参数，并转换成目标类型
	 * 
	 * @param type
	 *            目标类型
	 * @param bind
	 *            参数信息
	 * @return
	 */
	private Object getParameter(Class type, Bind bind) {
		if (bind == null || StringUtils.isBlank(bind.key())) {
			Object obj = null;
			try {
				obj = type.newInstance();
			} catch (InstantiationException e) {
				log
						.debug(
								"InstantiationException happened when initializing bussiness object",
								e);
				return null;
			} catch (IllegalAccessException e) {
				log
						.debug(
								"IllegalAccessException happened when initializing bussiness object",
								e);
				return null;
			}
			PopulatorFactory.getDefaultPopulator().populate(
					RequestContext.get().getRequest(), obj, null, null);
			return obj;
		}

		Object value = null;
		String key = bind.key();
		String defaultValue = bind.defaultValue();
		String params[] = (String[]) ((Map) RequestContext.get().getRequest()
				.getParameterMap()).get(key);
		if (params == null) {
			if (defaultValue != null)
				params = new String[1];
			else
				params = new String[0];
		}
		if (params.length == 0) {
			if (type.isArray()) {
				value = params;
			} else if (defaultValue != null)
				value = defaultValue;
		} else if (params.length == 1) {
			if (type.isArray())
				value = refillParameters(params, defaultValue);
			else
				value = refillParameters(params, defaultValue)[0];
		} else if (type.isArray()) {
			value = refillParameters(params, defaultValue);
		} else if (defaultValue != null) {
			value = defaultValue;
		} else {
			value = params[0] != null && params[0].length() != 0 ? ((Object) (params[0]))
					: null;
		}

		if(type == Timestamp.class){
			return ConverterFactory.getDefaultConverter().convertValue(Long.parseLong((String)value), type);
		}else{
			return ConverterFactory.getDefaultConverter().convertValue(value, type);
		}
	}

	private String[] refillParameters(String params[], String defaultValue) {
		if (params == null)
			return null;
		boolean useDefaultValue = defaultValue != null;
		for (int i = 0; i < params.length; i++)
			if (params[i] == null || params[i].length() == 0) {
				params[i] = null;
				if (useDefaultValue)
					params[i] = defaultValue;
			}

		return params;
	}

	protected Object getService(String name) {
		return BusinessServiceFactory.getService(RequestContext.get()
				.getServletContext(), name);
	}

	protected void error(String message) {
		RequestContext.get().setSuccess(false);
		RequestContext.get().setMessage(message);
	}

	protected void success(String message) {
		RequestContext.get().setSuccess(true);
		RequestContext.get().setMessage(message);
	}

	protected User getUser() {
		Object obj = RequestContext.get().getRequest().getSession()
				.getAttribute(Constants.LONGIN_USER);
//		if(obj==null){//test
//			User user = new User();
//			user.setId(new Long(1));
//			user.setFetionNo("11111");
//			obj=user;
//		}
		return obj == null ? null : (User)obj;
	}
	
}
